package cn.taskservice.common.exception;

import cn.taskservice.common.enums.ResultCode;
import cn.taskservice.common.utils.result.ResultUtil;
import cn.taskservice.common.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;

import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;

/**
 * 全局异常处理
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 处理自定义业务异常
     */
    @ExceptionHandler(ServiceException.class)
    public Result<?> handleServiceException(ServiceException ex) {
        log.error("业务异常: {}", ex.getMessage(), ex);
        return ResultUtil.failure(ex.getCode(), ex.getMessage());
    }

    /**
     * 处理空指针异常
     */
    @ExceptionHandler(NullPointerException.class)
    public Result<?> handleNullPointerException(NullPointerException ex) {
        log.error("空指针异常", ex);
        return ResultUtil.failure(ResultCode.NULL_POINTER.code(), ResultCode.NULL_POINTER.message());
    }

    /**
     * 处理类型转换异常
     */
    @ExceptionHandler(ClassCastException.class)
    public Result<?> handleClassCastException(ClassCastException ex) {
        log.error("类型转换异常", ex);
        return ResultUtil.failure(ResultCode.CLASS_CAST.code(), ResultCode.CLASS_CAST.message());
    }

    /**
     * 处理数据库异常
     */
    @ExceptionHandler(SQLException.class)
    public Result<?> handleSQLException(SQLException ex) {
        log.error("数据库异常", ex);
        return ResultUtil.failure(ResultCode.DB_ERROR.code(), ResultCode.DB_ERROR.message());
    }

    /**
     * 处理超时异常
     */
    @ExceptionHandler(TimeoutException.class)
    public Result<?> handleTimeoutException(TimeoutException ex) {
        log.error("系统超时异常", ex);
        return ResultUtil.failure(ResultCode.TIMEOUT.code(), ResultCode.TIMEOUT.message());
    }
    /**
     * 处理请求参数绑定异常，比如 @Valid 校验失败导致的 BindException
     */
    @ExceptionHandler(BindException.class)
    public Result<?> handleBindException(BindException ex) {
        log.error("请求参数绑定异常", ex);

        // 拼接所有字段的错误信息
        StringBuilder errorMsg = new StringBuilder();
        for (FieldError fieldError : ex.getFieldErrors()) {
            errorMsg.append(fieldError.getField())
                    .append(": ")
                    .append(fieldError.getDefaultMessage())
                    .append("; ");
        }

        return ResultUtil.failure(ResultCode.VALIDATE_FAILED.code(), errorMsg.toString());
    }

    /**
     * 处理 @RequestBody 参数校验异常，比如 @Valid 方式校验失败导致的 MethodArgumentNotValidException
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.error("请求体参数校验异常", ex);

        StringBuilder errorMsg = new StringBuilder();
        for (FieldError fieldError : ex.getBindingResult().getFieldErrors()) {
            errorMsg.append(fieldError.getField())
                    .append(": ")
                    .append(fieldError.getDefaultMessage())
                    .append("; ");
        }

        return ResultUtil.failure(ResultCode.VALIDATE_FAILED.code(), errorMsg.toString());
    }

    /**
     * 处理所有未捕获异常
     */
    @ExceptionHandler(Exception.class)
    public Result<?> handleException(Exception ex) {
        log.error("未知异常", ex);
        return ResultUtil.failure(ResultCode.UNKNOWN_ERROR.code(), ResultCode.UNKNOWN_ERROR.message());
    }

    /**
     * 自定义聚合异常处理，将多个异常信息合并
     * @param ex
     * @return
     */
    @ExceptionHandler(ValidationException.class)
    public Result<?> handleValidationException(ValidationException ex) {
        // 收集所有错误信息
        List<String> messages = ex.getErrors().stream()
                .map(Throwable::getMessage)
                .collect(Collectors.toList());

        // 将所有错误信息拼接返回，也可用 messages 作为返回结构的扩展字段
        return ResultUtil.failure(
                ResultCode.SERVER_ERROR.getCode(),
                String.join("; ", messages)
        );
    }
}
